/**
 *  @file
 *  @brief   Tetra4单元
 *  @author  kangrongyao
 *  @date    2024.05.15
 *  @version v1.0
 *  @par Copyright(c):  ShenGong  Simulation corporation
 */

#pragma once
#include "Utility/Algebra/Matrix.h"
#include "Utility/Algebra/Point.h"
#include "DataStructure/Common/Out.h"
#include "SGFem/Integration/IntegrationFormula/Gauss3DTetra4.h"
#include "SGFem/Integration/ShapeFunction/Tetra4NodeShpFunc.h"
#include "../Interface/IElementCalculator.h"

SG_FEMSOLVER_ELEMENT_NAMESPACE_OPEN
class ElementCalculator_DECLSPEC Tetra4ElementCalculator : public SG::FEMSolver::Element::IElementCalculator
{
  public:
    Tetra4ElementCalculator ()          = default;
    virtual ~Tetra4ElementCalculator () = default;

    /**
     * @brief    计算单元坐标系变换矩阵，将节点变换到单元坐标系下
     * 
     * @param    [in] pointSet Basic 坐标系单元节点坐标
     * @param    [out] T 单元坐标系变换矩阵
     * @param    [out] localCoord 单元坐标系单元节点坐标
     * @author   Du Weixing
     * @date     2025.04.28
     */
    static void CoordTrans (const SG::Algebra::PointArray& pointSet, _OUT SG::Algebra::Matrixd& T, _OUT SG::Algebra::Matrixd& localCoord);

    /**
     * @brief    计算基于单元的应力应变坐标系（即 mCId = -2）变换矩阵
     * 
     * @param    [in] pointSet Basic 坐标系单元节点坐标
     * @param    [out] TS 基于单元的应力应变坐标系（即 mCId = -2）变换矩阵
     * @author   Du Weixing
     * @date     2025.03.07
     */
    static void ComputeInternalCoordTrans (const SG::Algebra::PointArray& pointSet, _OUT SG::Algebra::Matrixd& TS);

    /**
     * @brief    应变矩阵计算
     * @author   wanghuan
     * @date     2025.02.25
     */
    void CalcBMatrix (const SG::Algebra::Matrixd& localCoord, _OUT SG::Algebra::Matrixd& B, _OUT SG::DataStructure::Common::Real& V);

    /**
     * @brief    计算单元坐标系下单元刚度矩阵
     *
     * @param    [in] localCoord 单元坐标系单元节点坐标
     * @param    [in] D 单元坐标系下材料弹性矩阵
     * @param    [out] kl 单元坐标系下单元刚度矩阵
     */
    void ComputeStiffness (const SG::Algebra::Matrixd& localCoord, const SG::Algebra::Matrixd& D, _OUT SG::Algebra::Matrixd& kl);

    /**
     * @brief    计算单元坐标系下单元应力刚度矩阵
     *
     * @param    [in] localCoord 单元坐标系单元节点坐标
     * @param    [in] eleEleCoordStress 单元坐标系下应力
     * @param    [out] kSigma 单元坐标系下单元应力刚度矩阵
     */
    void ComputeStressStiffness (const SG::Algebra::Matrixd& localCoord, const SG::Algebra::Matrixd& eleEleCoordStress, _OUT SG::Algebra::Matrixd& kSigma);


    /**
     * @brief    计算单元坐标系下单元集中质量矩阵
     *
     * @param    [in] localCoord 单元坐标系单元节点坐标
     * @param    [in] rho 材料密度
     * @param    [out] lumpedM 单元坐标系下单元集中质量矩阵
     */
    static void ComputeLumpedMass
    (
    const SG::Algebra::Matrixd&            localCoord,
    const SG::DataStructure::Common::Real& rho,
    _OUT SG::Algebra::Matrixd&             lumpedM
    );

    /**
     * @brief    计算单元坐标系下单元耦合质量矩阵
     * 
     * @param    [in] localCoord 单元坐标系单元节点坐标
     * @param    [in] rho 材料密度
     * @return   单元坐标系下单元耦合质量矩阵
     */
    SG::Algebra::Matrixd ComputeCoupledMass
    (
    const SG::Algebra::Matrixd&            localCoord,
    const SG::DataStructure::Common::Real& rho
    );

    /**
     * @brief    计算单元应力应变
     *
     * @param    [in] localCoord 单元坐标系单元节点坐标
     * @param    [in] D 单元坐标系下材料弹性矩阵
     * @param    [in] elementDisplacement 单元坐标系单元位移
     * @param    [in] TMat 单元的材料坐标系变换矩阵：单元坐标系到材料坐标系
     * @param    [out] elementStrain 单元应变
     * @param    [out] elementStress 单元应力
     * @author   Du Weixing
     * @date     2025.01.02
     */
    void ComputeElementStrainStress
    (
    const SG::Algebra::Matrixd& localCoord,
    const SG::Algebra::Matrixd& D,
    const SG::Algebra::Matrixd& elementDisplacement,
    const SG::Algebra::Matrixd& TMat,
    _OUT SG::Algebra::Matrixd&  elementStrain,
    _OUT SG::Algebra::Matrixd&  elementStress
    );

    virtual void Initialize (SG::DataStructure::FEM::ElementTypes type) override;
    virtual void ComputeElementMatries (const SG::DBManager::DBServiceFactorySP dbServiceFactory) override;
    virtual void DataRecovery
    (
    const SG::DBManager::DBServiceFactorySP             dbServiceFactory,
    int                                                 subcaseId, 
    SG::DataStructure::Common::Real time,
    const std::vector<SG::DataStructure::Common::Real>& globalDisplacement
    ) override;
    virtual void ComputeStressStiffness (const SG::DBManager::DBServiceFactorySP dbServiceFactory, int staticSubId) override;

    static ElementCalculatorSP Create ()
    {
        return std::make_shared<Tetra4ElementCalculator> ();
    }

  private:
    SG::DataStructure::FEM::ElementTypes      m_type;
    SG::FEMSolver::Element::Gauss3DTetra4     m_integCalc;
    SG::FEMSolver::Element::Tetra4NodeShpFunc m_shpFunc;
};

SG_FEMSOLVER_ELEMENT_NAMESPACE_CLOSE